package edu.utn.tacs.gestion.domain.impl;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Logger;

import edu.utn.tacs.gestion.exception.BusinessException;

/**
 * Representacion de un evento en el dominio de negocio<li>Un evento se identifica univocamente por sus atributos nombre y fecha</li>
 */
public class Evento {

	private String nombre;
	private Date fecha;
	private double duracion;
	private String descripcion;
	private String ubicacion;
	private Usuario owner;
	private Set<Usuario> usuariosRegistrados;
	private Set<Usuario> usuariosAsistentes;
	private Set<Comentario> comentarios;
	static Logger logger = Logger.getLogger(Evento.class);
	
	public Evento(){};
	
	public Evento(Usuario owner, String nombre, Date fecha, double duracion, String descripcion) {
		this.owner = owner;
		this.nombre = nombre;
		this.fecha = fecha;
		this.duracion = duracion;
		this.descripcion = descripcion;
		this.usuariosRegistrados = new HashSet<Usuario>();
		this.usuariosAsistentes = new HashSet<Usuario>();
		this.comentarios = new HashSet<Comentario>();
	}

	
	public String getNombre() {
		return nombre;
	}

	public void setNombre(String nombre) {
		this.nombre = nombre;
	}

	public Date getFecha() {
		return fecha;
	}

	public void setFecha(Date fecha) {
		this.fecha = fecha;
	}

	public double getDuracion() {
		return duracion;
	}

	public void setDuracion(double duracion) {
		this.duracion = duracion;
	}

	public String getDescripcion() {
		return descripcion;
	}

	public void setDescripcion(String descripcion) {
		this.descripcion = descripcion;
	}

	public String getUbicacion() {
		return ubicacion;
	}

	public void setUbicacion(String ubicacion) {
		this.ubicacion = ubicacion;
	}	
	
	public Usuario getOwner() {
		return owner;
	}
		
	public Set<Usuario> getUsuariosRegistrados() {
		return this.usuariosRegistrados;
	}
	
	public Set<Usuario> getUsuariosAsistentes() {
		return this.usuariosAsistentes;
	}
	
	public Set<Comentario> getComentarios() {
		return this.comentarios;
	}
	
	public boolean isUsuarioRegistrado(Usuario usuario) {
		logger.debug("Metodo: isUsuarioRegistrado()");
		return this.usuariosRegistrados.contains(usuario);
	}
	
	public Usuario findUsuarioRegistrado(Long nroDocumento) {
		logger.debug("Metodo: findUsuarioRegistrado()");	
		for(Usuario usuario: this.usuariosRegistrados) {
			if(usuario.getNroDocumento().equals(nroDocumento)) return usuario;
		}
		return null;
	}
	
	public Usuario findUsuarioAsistente(Long nroDocumento) {
		logger.debug("Metodo: findUsuarioAsistente()");
		for(Usuario usuario: this.usuariosAsistentes) {
			if(usuario.getNroDocumento().equals(nroDocumento)) return usuario;
		}
		return null;
	}
	
	/**
	 * Permite a un usuario agregar un comentario acerca del evento 
	 * @param usuario
	 */
	public void agregarComentario(Usuario usuario) {
		logger.debug("Metodo: agregarComentario()");
		Comentario ctrio = new Comentario();
		ctrio.setUsuario(usuario);
		ctrio.setDescripcion(usuario.getComentario());
		ctrio.setFecha(new Date());
	}

	/**
	 * Permite suscribir un usuario a un envento solo si el usuario no esta registrado previamente
	 * @param usuario
	 * @throws BusinessException
	 */
	public void suscribirAEvento(Usuario usuario) throws BusinessException {
		logger.debug("Metodo: suscribirAEvento()");
		if(this.usuariosRegistrados.contains(usuario)) {
			logger.error("BusinessException: ");
			throw new BusinessException("Usuario ya registrado en este evento");
		}
		this.usuariosRegistrados.add(usuario);
		logger.info("Usuario: " + usuario.getNombre() +" registrado en el Evento: " + this.getNombre());
	}
	
	
	/**
	 * Permite desuscribir un usuario a un envento solo si el usuario no esta registrado previamente
	 * @param usuario
	 * @throws BusinessException
	 */
	public void desuscribirAEvento(Usuario usuario) throws BusinessException {
		logger.debug("Metodo: desuscribirAEvento()");
		if(!(this.usuariosRegistrados.contains(usuario))) {
			logger.error("BusinessException: ");
			throw new BusinessException("Usuario ya registrado en este evento");
		}
		this.usuariosRegistrados.remove(usuario);
		logger.info("Se desuscribio a usuario: " + usuario.getNombre() + " del Evento: " + this.getNombre());
	}
	
	
	/**
	 * Permite cancelar la suscripcion a un evento solo si el evento no ocurrio
	 */
	public void cancelarSuscripcionAEvento(Usuario usuario) throws BusinessException {
		logger.debug("Metodo: cancelarSuscripcionAEvento()");
		if(this.usuariosRegistrados.contains(usuario)) {
			if (this.getFecha().after(new Date())) {
				this.getUsuariosRegistrados().remove(usuario);
			}
		} else {
			throw new BusinessException("Usuario no registrado en este evento");
		}
		logger.info("Se cancela la suscripcion del Usuario: " + usuario.getNombre() + " al Evento: " + this.nombre);
			
	}
	
	public void registrarAsistencia(Usuario usuario) {
		logger.debug("Metodo: registrarAsistencia()");
		this.usuariosAsistentes.add(usuario);
		logger.info("Se registra la asistencia del Usuario: " + usuario.getNombre() + " al Evento: " + this.getNombre());
	}
	
	public Comentario agregarComentario(Usuario usuario, String descripcion) {
		logger.debug("Metodo: agregarComentario()");
		Comentario comentario = new Comentario(usuario, descripcion, new Date());
		this.comentarios.add(comentario);
		logger.info("Se registro el Comentario: " + comentario.getDescripcion() + 
				" del Usuario: " + usuario.getNombre() + " al Evento: " + this.getNombre());
		return comentario;
	}
	
	public boolean existeComentario(Comentario comentario) {
		logger.debug("Metodo: existeComentario()");
		return this.getComentarios().contains(comentario);
	}
	
	
	/* (non-Javadoc)
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((fecha == null) ? 0 : fecha.hashCode());
		result = prime * result + ((nombre == null) ? 0 : nombre.hashCode());
		return result;
	}


	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) return true;
		if (obj == null) return false;
		if (!(obj instanceof Evento)) return false;
		Evento other = (Evento) obj;
		if (fecha == null) {
			if (other.fecha != null)
				return false;
		} else if (!fecha.equals(other.fecha))
			return false;
		if (nombre == null) {
			if (other.nombre != null)
				return false;
		} else if (!nombre.equals(other.nombre))
			return false;
		return true;
	}

	
}
